<!--
**********************************************************
* @Author: 张小平
* @Date:   2024-05-01
* @Email:  qqshuqian@163.com
* @Last modified: 最后修改日期
* @Description: 文件描述
**********************************************************
-->
<template>
  <div>
    <el-upload class="upload-demo" ref="upload" action="" :on-change="fileChange" :on-progress="fileProgress"
      :http-request="customerUpload" :before-upload="beforeUpload" :on-success="handleSuccess" :on-error="handleError"
      :auto-upload="false" :multiple="multiple" :show-file-list="false" :file-list="uploadFileList" :accept="mime">
      <template #trigger>
        <el-button size="small">选取文件</el-button>
      </template>
      <el-button class="ml_10" :disabled="!uploadFileList.length" size="small" type="primary"
        @click="submitUpload">上传</el-button>
    </el-upload>
    <!-- 文件列表信息 -->
    <div v-if="uploadFileList.length" class="progress-box">
      <div class="list-item">
        <div class="item-name">名称</div>
        <div class="item-size">大小</div>
        <div class="item-progress">文件进度</div>
        <div class="item-status">状态</div>
        <div class="item-operate">操作</div>
      </div>
      <div v-for="(item, index) in uploadFileList" :key="item.uid">
        <div class="list-item">
          <div class="item-name">
            <span>{{ index + 1 }}.{{ item.name }}</span>
          </div>
          <div class="item-size">
            {{ getFileSize(item.size) }}
          </div>
          <div class="item-progress">
            <el-progress :percentage="Number(item.percentage.toFixed(0))" />
          </div>
          <div class="item-status">
            <i :class="fileStatuIcon(item.status)"></i>
            {{ item.status | fileStatus }}
          </div>
          <div class="item-operate">
            <el-popconfirm v-if="item.status !='success'" hideIcon title="确定删除当前文件吗？" @confirm="delFile(index)">
              <template #reference>
                <span class="coldel pointer">删除</span>
              </template>
            </el-popconfirm>
          </div>
        </div>
      </div>
    </div>
    <div v-else class="progress-box vertical">请选择文件上传</div>
  </div>
</template>

<script>
import * as qiniu from "qiniu-js";
import { getQiniuToken }  from '@/framework-core/api/upload/qiniu';
// 单个文件的状态 对应描述
const fileStatus = {
  ready: {
    code: "ready",
    name: "待上传",
  },
  wait: {
    code: "wait",
    name: "待上传",
  },
  uploading: {
    code: "uploading",
    name: "上传中",
  },
  success: {
    code: "success",
    name: "成功",
  },

  fail: {
    code: "fail",
    name: "失败",
  },
  error: {
    code: "error",
    name: "失败",
  },
  secondPass: {
    code: "secondPass",
    name: "已秒传",
  },
  pause: {
    code: "pause",
    name: "暂停",
  },
  resume: {
    code: "resume",
    name: "恢复",
  },
};
export default {
  props: {
    checkFun: { type: Function, default: function () { return true } },
    max: { type: Number, default: 104857600 },
    mime: { type: Array, default: Array }, //后台限制的文件格式
    multiple: { default: true }
  },
  data() {
    return {
      spaceData: {
        domain: "",
        token: "",
        catalogue: ""
      },
      uploadFileList: [] //上传文件列表  {name,size,percentage,status,uid}  uid唯一标识
    };
  },

  filters: {
    fileStatus(status) {
      return fileStatus[status].name;
    },
  },
  computed: {
    //文件上传状态的图标
    fileStatuIcon() {
      return function (status) {
        let className = "";
        switch (status) {
          case "uploading":
            className = "el-icon-loading";
            break;
          case "success":
          case "secondPass":
            className = "el-icon-circle-check";
            break;
          case "error":
            className = "el-icon-circle-close";
            break;
        }
        return className;
      };
    },
  },
  mounted() {
    getQiniuToken().then((res) => {
      this.spaceData.token = res.token
      this.spaceData.domain = res.domain
      this.spaceData.catalogue = res.catalogue
    }).catch((e) => {
      this.$message.error(e.message);
    });
  },
  methods: {
    //手动上传文件
    submitUpload() {
      this.$refs.upload.submit();
    },

    //附件改变（增加删除时）
    fileChange(file, fileList) {
      const index = this.uploadFileList.findIndex(
        (item) => item.name == file.name
      );
      if (index == -1) {
        if (this.multiple) {
          this.uploadFileList = fileList;
        } else {
          if (this.uploadFileList.length > 0) {
            this.$message.error("只能上传一个文件");
          } else {
            this.uploadFileList = fileList;
          }
        }
      }
    },

    /**
     * @description: 上传中的处理 让文件列表数据于显示的文件列表数据相同
     * @param {*} event
     * @param {*} file
     * @param {文件列表} fileList
     * @return {*}
     */
    fileProgress(event, file, fileList) {
      this.uploadFileList = fileList;
    },

    /**
     * @description: 上传之前的文件处理
     * @param {待上传文件信息} file
     * @return {*}
     */
    beforeUpload(file) {
      const isLt2M = file.size < this.max;
      if (!isLt2M) {
        this.$message.warning(`${file.name}文件过大，不能超出${this.max / 1024 / 1024}M！`);
        return isLt2M;
      }
      var type = true;
      if (this.mime instanceof Array) {
        if (this.mime && this.mime.length > 0) {
          type = this.mime.includes(file.type);
          if (!type) {
            this.$message.warning(`${file.name}文件类型不允许！`);
            return type;
          }
        }
      } else {
        if (this.mime) {
          type = this.mime.indexOf(file.type);
        }
      }
      //外部的校验方法
      var check = this.checkFun(file, this.multiple);

      return isLt2M && type && check;
    },

    /**
     * @description: 上传成功后的向父组件同步文件数据
     * @param {上传成功后接口返回的数据} res
     * @param {当前上传的文件信息} file
     * @return {*}
     */
    handleSuccess(res, file) {
      const file_name = file.name.substring(0, file.name.lastIndexOf("."));
      const file_ext = file.name.substring(file.name.lastIndexOf(".") + 1, file.name.length);
      const file_size = file.size;
      const file_path = "https://" + this.spaceData.domain + `/${res.key}`; //七牛云上绑定的域名 拼接了这个key 就是你上传文件的地址了
      this.$emit('done', file_name, file_ext, file_size, file_path);
    },
    //上传错误处理
    handleError(err) {
      this.$message.error(err);
    },
    /**
     * @description: 删除文件,不能删除已经上传完成的
     * @param {*文件名称} name
     * @param {*数据在uploadFileList的当前下标} index
     * @return {*}
     */
    delFile(index) {
      if (this.uploadFileList[index].status == "success") {
        return;
      }
      //如果还未上传成功
      if (this.uploadFileList[index].status == "uploading") {
        this.uploadFileList[index].subscription.unsubscribe()
      }
      this.uploadFileList.splice(index, 1);
    },

    upload(token, key, obj, next, error, complete) {
      const { file } = obj;
      const putExtra = {
        // fname: file.name, // fname: string，文件原文件名
        params: {}, // params: object，用来放置自定义变量
        mimeType: null, // mimeType: null || array，用来限制上传文件类型，为 null 时表示不对文件类型限制；限制类型放到数组里： ["image/png", "image/jpeg", "image/gif"]
      },
        config = {
          useCdnDomain: true
        };
      let observable = qiniu.upload(file, key, token, putExtra, config);
      let subscription = observable.subscribe(next, error, complete);
      return subscription;
    },

    //上传七牛云
    customerUpload(request) {
      const { file } = request;
      const uid = file.uid;
      const item = this.uploadFileList.find((item) => item.uid == uid);
      let token = this.spaceData.token;
      let key = file.name;
      if (this.spaceData.catalogue) {
        key = this.spaceData.catalogue + "/" + key;
      }
      var up = this.upload(token, key, request, (next) => {
        let total = next.total;
        //设置进度条
        this.$set(item, "percentage", total.percent);
        this.$set(item, "status", "uploading");
      },
        (error) => {
          request.onError(error);
        },
        (complete) => {
          request.onSuccess(complete);
        }
      );
      this.$set(item, "subscription", up);
    },
    getFileSize(fileByte) {
      var fileSizeByte = fileByte;
      var fileSizeMsg = "";
      if (fileSizeByte < 1048576) fileSizeMsg = (fileSizeByte / 1024).toFixed(2) + "KB";
      else if (fileSizeByte == 1048576) fileSizeMsg = "1MB";
      else if (fileSizeByte > 1048576 && fileSizeByte < 1073741824) fileSizeMsg = (fileSizeByte / (1024 * 1024)).toFixed(2) + "MB";
      return fileSizeMsg;
    },
  },
};
</script>

<style lang="scss" scoped>
.font13 {
  font-size: 13px;
}
.col2c {
  color: #2c6ee5;
}
.coldel {
  color: #e91c47;
}
.pointer {
  cursor: pointer;
}
.in_block {
  display: inline-block;
}
.vertical {
  display: flex;
  align-items: center;
  justify-content: center;
}
.verticall {
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
.ml_10 {
  margin-left: 10px;
}
.mr_10 {
  margin-right: 10px;
}
.progress-box {
  min-height: 260px;
  width: 100%;

  .list-item {
    padding: 8px 10px;
    display: flex;
    justify-content: center;
    align-items: center;
    line-height: 25px;
    position: relative;

    .item-name {
      flex: 2;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      margin-right: 6px;
    }
    .item-size {
      flex: 1;
    }
    .item-progress {
      flex: 2;
      padding-right: 30px;
    }
    .item-status {
      flex: 1;
      .el-icon-circle-check {
        color: #67c23a;
      }
      .el-icon-circle-close {
        color: #f00;
      }
    }
    .item-operate {
      flex: 1;
    }
  }
}
</style>
